package com.eimf.saf.common.commons.tag;

import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.eimf.saf.common.entity.Dict;
import com.eimf.saf.common.filter.I18nIntercept;
import com.eimf.saf.common.util.CommonCache;
import com.opensymphony.xwork2.util.LocalizedTextUtil;

/**
 * @author eden
 * @date 2013-11-14 下午6:21:23
 * @Description: 字典控件
 */
public abstract class DictTag extends TagSupport
{
    private static final long serialVersionUID = 1L;

    private static Log logger = LogFactory.getLog(DictTag.class);

    // 以下为标签对应的属性，除code、showTip、selectValue为自定义属性外，其它均为select标签属性
    private String id;
    private String name;
    private String style;
    private String className;
    private String tabIndex;
    private String onchange;
    private Boolean isCreateLable = false;// 是自动创建Lable
    private String showTipInfo;// 提示信息

    private String selectValue; // 支持多个值,以","分割
    private Boolean showTip = true;
    private String filterStr;
    private String dictType;

    private String datatype;// 验证框架增加的属性
    private String errormsg;// 验证框架增加的属性

    private Boolean isDESC = false;// 是否降序

    /** 控件类型 */
    private String controlType;
    private static String CONTROL_TYPE_SELECT = "1";
    private static String CONTROL_TYPE_RADIO = "2";
    private static String CONTROL_TYPE_LABLE = "3";
    private static String CONTROL_TYPE_CHECKBOX = "4";
    private static String CONTROL_TYPE_TABLEVALUE = "5";
    private static String CONTROL_TYPE_LIST = "6";// ul控件标签

    // private static String SHOW_TIP_INFO = "-------";

    @Override
    public int doStartTag() throws JspException
    {
        try
        {
            final List<Dict> dictList = getDictListByTypeList(dictType);
            removeFilterForList(dictList);

            if (isDESC != null)
            {
                Collections.sort(dictList, new DictVOComparator(isDESC));
            }

            if (DictTag.CONTROL_TYPE_SELECT.equals(controlType))
            {
                generationSelectHTML(dictList);
            } else if (DictTag.CONTROL_TYPE_RADIO.equals(controlType))
            {
                generationRadioHTML(dictList);
            } else if (DictTag.CONTROL_TYPE_LABLE.equals(controlType))
            {
                generationLableHTML(dictList);
            } else if (DictTag.CONTROL_TYPE_CHECKBOX.equals(controlType))
            {
                generationCheckBoxHTML(dictList);
            } else if (DictTag.CONTROL_TYPE_TABLEVALUE.equals(controlType))
            {
                generationTableHTML(dictList);
            } else if (DictTag.CONTROL_TYPE_LIST.equals(controlType))
            {
                generationListHTML(dictList);
            }

        } catch (final Exception e)
        {
            DictTag.logger.error(e.getMessage(), e);
        }
        return Tag.EVAL_BODY_INCLUDE;
    }

    /**
     * 获取指定类型下的字典列表。<br>
     * 使用字典标签的时候，需要实现本方法。
     * 
     * @param dictType
     * @return
     */
    public abstract List<Dict> getDictListByTypeList(String dictType);

    /**
     * 删除指定filterStr存在的项。
     * 
     * @param dictList
     */
    private void removeFilterForList(final Collection<Dict> dictList)
    {
        if (filterStr != null && filterStr.trim().length() > 0)
        {
            final String[] filterIds = filterStr.split(",");
            final Iterator<Dict> iterator = dictList.iterator();
            while (iterator.hasNext())
            {
                final Dict item = iterator.next();
                for (final String fid : filterIds)
                {
                    if (item.getDictTypeId().equals(dictType) && item.getDictId().equals(fid))
                    {
                        iterator.remove();
                    }
                }
            }
        }
    }

    /**
     * 生成LABLE控件。
     * 
     * @param dictList
     * @throws IOException
     */
    private void generationLableHTML(final Collection<Dict> dictList) throws IOException
    {
        final StringBuffer out = new StringBuffer();
        String[] values = null;
        if (null != selectValue && !"".equals(selectValue))
        {
            values = selectValue.split(",");
        }
        out.append("<span");
        if (this.id != null)
        {
            out.append(" id=\"" + this.id + "\"");
        }
        if (this.name != null)
        {
            out.append(" name=\"" + this.name + "\"");
        }
        if (this.className != null)
        {
            out.append(" class=\"" + this.className + "\"");
        }
        out.append(">");
        if (values != null && values.length > 0)
        {
            String temp;
            for (int i = 0; i < values.length; i++)
            {
                temp = values[i];
                if (i > 0)
                {
                    out.append("、");
                }
                for (final Dict item : dictList)
                {
                    if (temp.equals(item.getDictId()))
                    {
                        out.append(item.getDictName());
                        break;
                    }
                }
            }
        }
        out.append("</span>");
        pageContext.getOut().write(out.toString());
    }

    /**
     * 根据list内容动态输出该HTML脚本。<br>
     * 默认情况下会有“请选择...”选项,如果有默认选择值但在列表不存在，则会默认选择“请选择...”项;<br>
     * 如果showTip=false即“请选择...”，如果有默认选择值但不存在，将会默认选择第一项;<br>
     * 控件的value值为DictVO的dictCode;<br>
     * <p>
     * 生成的示例： <SELECT id="participantType" name="participantType"
     * onchange="showChange();" style="width:110px"> <OPTION VALUE="001"
     * >个人</OPTION> <OPTION VALUE="002" >企业</OPTION> </SELECT>
     * </p>
     * 
     * @param list
     * @throws Exception
     */
    private void generationSelectHTML(final Collection<Dict> list) throws Exception
    {
        final StringBuffer out = new StringBuffer();
        final StringBuffer temp = new StringBuffer();
        boolean isBeSelected = false;// 标识默认选择值是否存在

        out.append("<SELECT ");
        if (this.id != null)
        {
            out.append(" id=\"" + this.id + "\"");
        }
        if (this.name != null)
        {
            out.append(" name=\"" + this.name + "\"");
        } else
        {
            throw new Exception("The 'name' attrib not null! ");
        }
        if (this.className != null)
        {
            out.append(" class=\"" + this.className + "\"");
        }
        if (this.onchange != null)
        {
            out.append(" onchange=\"" + this.onchange + "\"");
        }
        if (this.tabIndex != null)
        {
            out.append(" tabIndex=\"" + this.tabIndex + "\"");
        }
        if (this.style != null)
        {
            out.append(" style=\"" + this.style + "\"");
        }
        if (this.datatype != null)
        {
            out.append(" datatype=\"" + this.datatype + "\"");
        }
        if (this.errormsg != null)
        {
            out.append(" errormsg=\"" + this.errormsg + "\"");
        }
        out.append(">\n");

        for (final Dict item : list)
        {
            if (item.getDictName() != null && item.getDictId().equals(this.selectValue))
            {
                isBeSelected = true;
                temp.append("<OPTION VALUE=\"" + item.getDictKey() + "\"  SELECTED>" + item.getDictName()
                        + "</OPTION>\n");
            } else
            {
                temp.append("<OPTION VALUE=\"" + item.getDictKey() + "\"  >" + item.getDictName() + "</OPTION>\n");
            }
        }

        if (isBeSelected && showTip)
        {
            out.append("<OPTION  value=\"\">");
            if (showTipInfo != null)
            {
                out.append(showTipInfo);
            } else
            {
                out.append(getDefaultShowTipInfo());
            }
            out.append("</OPTION>\n");
        } else if (showTip)
        {
            out.append("<OPTION  SELECTED value=\"\">");
            if (showTipInfo != null)
            {
                out.append(showTipInfo);
            } else
            {
                out.append(getDefaultShowTipInfo());
            }
            out.append("</OPTION>\n");
        }

        out.append(temp);
        out.append("</SELECT>\n");
        pageContext.getOut().write(out.toString());
    }

    /**
     * 根据list内容动态输出该HTML脚本。<br>
     * id的生成较特殊，是根据id名再加索引值来构成的,<br>
     * 控件的value值为SysrefcodeDO的主键,控件的code值为SysrefcodeDO的value;<br>
     * ;
     * <p>
     * 示例： <div id="sex"> <INPUT TYPE="radio" name="sex" id="sex0"
     * class="validate-one-required" tabIndex="2" code="1"
     * value="17">男&nbsp;</INPUT> <INPUT TYPE="radio" name="sex" id="sex1"
     * class="validate-one-required" tabIndex="2" code="0"
     * value="18">女&nbsp;</INPUT> </div>
     * </p>
     * 
     * @param list
     * @throws Exception
     */
    private void generationRadioHTML(final Collection<Dict> list) throws Exception
    {
        final StringBuffer out = new StringBuffer();

        int i = 0;// 用于组合ID
        out.append("<span id=\"" + this.id + "\">\n");
        for (final Dict item : list)
        {
            if (isCreateLable)
            {
                out.append("<label>");
            }

            out.append("<INPUT TYPE=\"radio\" ");
            if (this.name != null)
            {
                out.append(" name=\"" + this.name + "\"");
            } else
            {
                throw new Exception("The 'name' attrib not null! ");
            }
            if (this.id != null)
            {
                out.append(" id=\"" + this.id + (i++) + "\"");
            }
            if (this.className != null)
            {
                out.append(" class=\"" + this.className + "\"");
            }
            if (this.onchange != null)
            {
                out.append(" onchange=\"" + this.onchange + "\"");
            }
            if (this.tabIndex != null)
            {
                out.append(" tabIndex=\"" + this.tabIndex + "\"");
            }
            if (this.style != null)
            {
                out.append(" style=\"" + this.style + "\"");
            }
            out.append(" value=\"" + item.getDictId() + "\"");
            if (this.selectValue != null && this.selectValue.equals(String.valueOf(item.getDictId())))
            {
                out.append("checked=\"checked\" ");
            }
            out.append(">" + item.getDictName() + "&nbsp;");
            out.append("</INPUT>\n");

            if (isCreateLable)
            {
                out.append("</label>");
            }
        }
        out.append("</span>\n");
        pageContext.getOut().write(out.toString());
    }

    private void generationCheckBoxHTML(final Collection<Dict> list) throws Exception
    {
        final StringBuffer out = new StringBuffer();
        final String[] selectValues = this.selectValue != null ? this.selectValue.split(",") : new String[] {};

        int i = 0;// 用于组合ID
        out.append("<span id=\"" + this.id + "\">\n");
        for (final Dict item : list)
        {
            if (isCreateLable)
            {
                out.append("<label>");
            }

            out.append("<INPUT TYPE=\"checkbox\" ");
            if (this.name != null)
            {
                out.append(" name=\"" + this.name + "\"");
            } else
            {
                throw new Exception("The 'name' attrib not null! ");
            }
            if (this.id != null)
            {
                out.append(" id=\"" + this.id + (i++) + "\"");
            }
            if (this.className != null)
            {
                out.append(" class=\"" + this.className + "\"");
            }
            if (this.onchange != null)
            {
                out.append(" onchange=\"" + this.onchange + "\"");
            }
            if (this.tabIndex != null)
            {
                out.append(" tabIndex=\"" + this.tabIndex + "\"");
            }
            if (this.style != null)
            {
                out.append(" style=\"" + this.style + "\"");
            }
            out.append(" value=\"" + item.getDictKey() + "\"");
            for (final String value : selectValues)
            {
                if (value.trim().equals(String.valueOf(item.getDictKey())))
                {
                    out.append("checked=\"checked\" ");
                }
            }
            out.append(">" + item.getDictName() + "&nbsp;");
            out.append("</INPUT>\n");

            if (isCreateLable)
            {
                out.append("</label>");
            }
        }
        out.append("</span>\n");
        pageContext.getOut().write(out.toString());
    }

    /**
     * 生成UL控件脚本。
     * 
     * @param list
     * @throws Exception
     */
    private void generationListHTML(final Collection<Dict> list) throws Exception
    {
        final StringBuffer out = new StringBuffer();
        out.append("<ul");
        if (this.id != null)
        {
            out.append("ID=").append(this.id);
        }
        out.append(">");

        if (showTip)
        {
            if (showTipInfo != null && showTipInfo.trim().length() > 0)
            {
                out.append("<li>").append(showTipInfo).append("</li>");
            } else
            {
                out.append("<li>").append(getDefaultShowTipInfo()).append("</li>");
            }
        }

        for (final Dict item : list)
        {
            out.append("<li code='").append(item.getDictKey()).append("'>");
            out.append(item.getDictName());
            out.append("</li>");
        }
        out.append("</ul>");

        pageContext.getOut().write(out.toString());
    }

    private void generationTableHTML(final List<Dict> list) throws Exception
    {
        final StringBuffer out = new StringBuffer();
        String temp = "";
        try
        {
            out.append("{");
            for (final Dict item : list)
            {
                out.append("\"" + item.getDictKey() + "\":\"" + item.getDictName() + "\"," + "\"" + item.getDictKey()
                        + "_remark" + "\":\"" + item.getRemark() + "\",");

            }
            out.append("}");
            temp = out.substring(0, (out.toString().length() - 2)) + "}";
        } catch (final Exception e)
        {
            DictTag.logger.error(e.getMessage(), e);
        }
        pageContext.getOut().write(temp);
    }

    /**
     * 返回缺省的请选择国际化信息. 294为“请选择”的国际化ID
     * 
     * @return
     */
    private String getDefaultShowTipInfo()
    {
        return CommonCache.getInternationInfo("1", I18nIntercept.getLanguage());
    }

    public String getClassName()
    {
        return className;
    }

    public void setClassName(final String className)
    {
        this.className = className;
    }

    @Override
    public String getId()
    {
        return id;
    }

    @Override
    public void setId(final String id)
    {
        this.id = id;
    }

    public String getName()
    {
        return name;
    }

    public void setName(final String name)
    {
        this.name = name;
    }

    public String getOnchange()
    {
        return onchange;
    }

    public void setOnchange(final String onchange)
    {
        this.onchange = onchange;
    }

    public String getSelectValue()
    {
        return selectValue;
    }

    public void setSelectValue(final String selectValue)
    {
        this.selectValue = selectValue;
    }

    public String getTabIndex()
    {
        return this.tabIndex;
    }

    public void setTabIndex(final String tableIndex)
    {
        this.tabIndex = tableIndex;
    }

    public String getStyle()
    {
        return style;
    }

    public void setStyle(final String style)
    {
        this.style = style;
    }

    public Boolean getShowTip()
    {
        return showTip;
    }

    public void setShowTip(final Boolean showTip)
    {
        this.showTip = showTip;
    }

    public String getFilterStr()
    {
        return filterStr;
    }

    public void setFilterStr(final String filterStr)
    {
        this.filterStr = filterStr;
    }

    public String getDictType()
    {
        return dictType;
    }

    public void setDictType(final String dictType)
    {
        this.dictType = dictType;
    }

    public String getControlType()
    {
        return controlType;
    }

    public void setControlType(final String controlType)
    {
        this.controlType = controlType;
    }

    public Boolean getIsDESC()
    {
        return isDESC;
    }

    public void setIsDESC(final Boolean isDESC)
    {
        this.isDESC = isDESC;
    }

    public Boolean getIsCreateLable()
    {
        return isCreateLable;
    }

    public void setIsCreateLable(final Boolean isCreateLable)
    {
        this.isCreateLable = isCreateLable;
    }

    public String getShowTipInfo()
    {
        return showTipInfo;
    }

    public void setShowTipInfo(final String showTipInfo)
    {
        this.showTipInfo = showTipInfo;
    }

    public String getDatatype()
    {
        return datatype;
    }

    public void setDatatype(final String datatype)
    {
        this.datatype = datatype;
    }

    public String getErrormsg()
    {
        return errormsg;
    }

    public void setErrormsg(final String errormsg)
    {
        if (errormsg != null)
        {
            final String temp = LocalizedTextUtil.findDefaultText(errormsg, I18nIntercept.getRequest().getLocale());
            this.errormsg = temp;
        }
    }
}

/**
 * 字典表的排放比较器。
 */
class DictVOComparator implements Comparator<Dict>
{
    private final Boolean isDesc;

    public DictVOComparator(final Boolean isDesc)
    {
        this.isDesc = isDesc;
    }

    public DictVOComparator()
    {
        this.isDesc = false;
    }

    @Override
    public int compare(final Dict o1, final Dict o2)
    {
        if (isDesc)
        {
            if (o2.getSortNo() > o1.getSortNo())
            {
                return 1;
            } else if (o2.getSortNo().equals(o1.getSortNo()))
            {
                return 0;
            } else
            {
                return -1;
            }
        } else
        {
            if (o1.getSortNo() > o2.getSortNo())
            {
                return 1;
            } else if (o1.getSortNo().equals(o2.getSortNo()))
            {
                return 0;
            } else
            {
                return -1;
            }
        }
    }
}
